教育示範用,非商品精算;真實商品需大量資料、監管與精算檢核。
import random, math, csv
random.seed(42) # 讓結果可重現(教學用)
# ---- 模型參數(你可以改這裡)----
N_POLICY = 1000 # 模擬保戶數
LAMBDA_CLAIM = 0.30 # 每保戶每年的「平均事故件數」(Poisson λ)
DEDUCTIBLE = 5_000 # 免賠額(每次事故,先自付這麼多)
COINSURANCE = 0.10 # 共付比(自付比例 10% → 保險公司理賠 90%)
LIMIT_PER_CLAIM = 200_000 # 單次事故理賠上限
EXPENSE_LOADING = 0.20 # 營運/通路加成(示意 20%)
# 事故金額分布(用三角分布,直覺易懂且不需外部套件)
# low=8,000,高=300,000,最可能值(mode)=60,000(單位:TWD)
def sample_severity():
return random.triangular(8_000, 300_000, 60_000)
# Knuth 演算法取樣 Poisson(λ)(標準庫無現成函式)
def sample_poisson(lmbda: float) -> int:
L = math.exp(-lmbda)
k, p = 0, 1.0
while p > L:
k += 1
p *= random.random()
return k - 1
def simulate_once(
n_policy=N_POLICY, lam=LAMBDA_CLAIM,
deductible=DEDUCTIBLE, coins=COINSURANCE, limit=LIMIT_PER_CLAIM
):
total_gross = 0.0 # 事故原始金額總和
total_payout = 0.0 # 保險公司實際支付
total_claims = 0
claimants = set()
rows = []
for pid in range(1, n_policy + 1):
n_claims = sample_poisson(lam)
if n_claims > 0:
claimants.add(pid)
for j in range(n_claims):
gross = sample_severity()
covered = max(gross - deductible, 0.0) # 扣免賠額後可理賠部分
payout = min(covered * (1 - coins), limit) # 扣共付比+上限
total_gross += gross
total_payout += payout
total_claims += 1
rows.append({
"policy_id": pid,
"claim_no": j + 1,
"gross": round(gross, 2),
"payout": round(payout, 2)
})
pure_premium = total_payout / n_policy if n_policy else 0.0
suggested_premium = pure_premium * (1 + EXPENSE_LOADING)
summary = {
"保戶數": n_policy,
"事故件數": total_claims,
"出險率_件/保單": round(total_claims / n_policy, 3),
"至少出險一次的保戶占比": round(len(claimants) / n_policy, 3),
"總事故金額_TWD": round(total_gross, 2),
"總理賠金額_TWD": round(total_payout, 2),
"純保費_每張保單_TWD": round(pure_premium, 2),
"建議保費(含20%加成)_TWD": round(suggested_premium, 2),
"條款": {
"免賠額": deductible,
"共付比": coins,
"每次理賠上限": limit
}
}
return summary, rows
# ---- 進行一次模擬並輸出結果 ----
summary, rows = simulate_once()
print("=== 模擬結果(方案A)===")
for k, v in summary.items():
if k != "條款":
print(f"{k}: {v}")
print("條款:", summary["條款"])
# 可選:存檔,之後拿去做圖或做報表
with open("claims_sim.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=["policy_id","claim_no","gross","payout"])
writer.writeheader()
writer.writerows(rows)
print("\n已輸出明細:claims_sim.csv")
# ---- What-if:調高免賠額到 10,000 再跑一次(比較保費變化)----
summary_B, _ = simulate_once(deductible=10_000)
print("\n=== 模擬結果(方案B:免賠額 10,000)===")
for k, v in summary_B.items():
if k != "條款":
print(f"{k}: {v}")
print("條款:", summary_B["條款"])